#!/usr/bin/env python3

# Copyright (c) 2005-2014 Fpemud <fpemud@sina.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import os
import glob
import json
import mrget
import shutil
import subprocess
from datetime import datetime


class DataSource(DataSourceBase):

    def __init__(self, tmp_dir):
        self._tmpDir = tmp_dir

    @property
    def name(self):
        return "iptv-org"

    @property
    def description(self):
        return ""

    @property
    def homepage(self):
        return "https://iptv-org.github.io"

    @property
    def supported_etypes(self):
        return ["ipvt-live-source"]

    @property
    def last_sync_datetime(self):
        return datetime.min

    def sync(self, common):
        url = mrget.target_urls("https://iptv-org.github.io/api/channels.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/streams.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/guides.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/categories.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/categories.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/languages.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/countries.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/subdivisions.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/regions.json")
        url = mrget.target_urls("https://iptv-org.github.io/api/blocklist.json")

    def has_game(self, common, game_platform, game_name):
        data = self._parseGamesJson(common.cache_dir)
        if data is None:
            raise ProviderNotSynchronized(self.name)

        if game_platform != GamePlatform.DOS:
            return False
        if game_name not in data:
            return False
        return True

    def list_games(self, common):
        if not self._isGamesJsonExist(common.cache_dir):
            raise ProviderNotSynchronized(self.name)

        ret = []
        for k, v in self._parseGamesJson(common.cache_dir).items():
            if k != v["identifier"]:
                raise BadProviderContent(self.name, "Bad data for game \"%s\" in data source \"%s\"" % (k, self.name))
            ret.append(GameId("dos", k))
        return ret

    def get_game_info(self, common, game_platform, game_name):
        ret = self._parseGamesJson(common.cache_dir).get(game_platform, game_name)
        if ret is None:
            raise SourceNotInProvider(self.name, game_platform, game_name)
        else:
            return GameInfo(
                default_language="zh_CN",
                names=self._toNames(ret),
                release_year=ret.get("releaseYear"),
            )

        # "executable": "PM2.COM",
        # "links": {
        #     "Princess Maker 2 - Wikipedia": "https://en.wikipedia.org/wiki/Princess_Maker_2"
        # },
        # "coverFilename": "cover.jpg",

    def _isGamesJsonExist(self, cacheDir):
        fullfn = os.path.join(cacheDir, "game.json")
        return os.path.exists(fullfn)

    def _parseGamesJson(self, cacheDir):
        jsonData = None
        with open(os.path.join(cacheDir, "game.json"), "r") as f:
            jsonData = json.load(f)["games"]
        return jsonData

    def _toNames(self, oneGameData):
        ret = {}
        if "zh-Hans" in oneGameData:
            ret["zh_CN"] = oneGameData["zh-Hans"]
        if "zh-Hant" in oneGameData:
            ret["zh_TW"] = oneGameData["zh-Hant"]
        if "en" in oneGameData:
            ret["en_US"] = oneGameData["en"]
        return ret


class Util:

    @staticmethod
    def gitPull(url, path):
        if os.path.exists(path):
            for fullfn in glob.glob(os.path.join(path, ".git", "**", "*.lock"), recursive=True):
                # FIXME:
                # should detect if this lock file is currently occupied by a git process?
                # git simply creates a plain file, or creates a real lock file?
                Util.force_rm(fullfn)
            subprocess.run(["git", "-C", path, "reset", "-q", "--hard"])  # revert any modifications
            subprocess.run(["git", "-C", path, "clean", "-q", "-xfd"])    # delete untracked files
            with TempChdir(path):
                subprocess.run(["/usr/libexec/robust_layer/git", "pull", "-q"])
        else:
            # FIXME: check url
            subprocess.run(["git", "clone", "-q", url, path])

    @staticmethod
    def force_rm(path):
        if os.path.islink(path):
            os.remove(path)
        elif os.path.isfile(path):
            os.remove(path)
        elif os.path.isdir(path):
            shutil.rmtree(path)
        elif os.path.lexists(path):
            os.remove(path)             # other type of file, such as device node
        else:
            pass                        # path does not exist, do nothing


class TempChdir:

    def __init__(self, dirname):
        self.olddir = os.getcwd()
        os.chdir(dirname)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        os.chdir(self.olddir)
